#ifndef __MEM_POOL_H__
#define __MEM_POOL_H__

#include "configure.h"

#define MEMORY_POOL_TYPE_MEMORY         0x0001
#define MEMORY_POOL_TYPE_HUGE_PAGE      0x0002

#define MEMORY_POOL_FLAG_FIXED          0x10000

#define MEM_POOL_PAGE_SIZE              4096

typedef struct mem_pool{
        int                     shmid[2];
        uint32_t                flags;
        uint32_t                page_size;
        uint32_t                page_count;
        void                    *base_addr;
        void                    *buddy_addr;
        void                    *mem_pool_addr;    //paged addr.
        struct mem_pool         *next;
} mem_pool_t;

#define MAX_MEMORY_TYPE_INDEX                   8

#define MEMORY_TYPE_INDEX_MALLOC                0
#define MEMORY_TYPE_INDEX_RING                  1
#define MEMORY_TYPE_INDEX_LSV                   2
#define MEMORY_TYPE_INDEX_BITMAP_CACHE          3

#define MEM_RING_SIZE_PER_CORE                  (64 * 1024 * 1024)

static const uint64_t DEFAULT_MEM_POOL_SIZE_ARRAY[4] =
{
        ((uint64_t)128 * 1024 * 1024),
        ((uint64_t)64 * 1024 * 1024),
        ((uint64_t)256 * 1024 * 1024),
        ((uint64_t)512 * 1024 * 1024),
};

#define DEFAULT_MEM_POOL_SIZE(x) DEFAULT_MEM_POOL_SIZE_ARRAY[x]

#ifndef likely
#define likely(x)  __builtin_expect((x),1)
#endif /* likely */

#ifndef unlikely
#define unlikely(x)  __builtin_expect((x),0)
#endif /* unlikely */

mem_pool_t *mem_pool_get(int index);    //create if.
void mem_pool_put(int index);

int mem_pool_init(mem_pool_t *pool, void *base_addr, uint32_t size, int flags);

void *mem_pool_alloc(mem_pool_t *pool, uint32_t mem_size);
void mem_pool_free(mem_pool_t *pool, void *mem_addr);

void *ring_pool_create(const char *name, size_t count, size_t ele_size);
void ring_pool_free(void *ring_ptr);

void ring_pool_push(void *ring_ptr, void **items, uint32_t count);
int ring_pool_pop(void *ring_ptr, void **items, uint32_t count);

void *ring_create(const char *name, size_t max_count);
void ring_free(void *ring_ptr);
void ring_push(void *ring_ptr, void **items, uint32_t count);
int ring_pop(void *ring_ptr, void **items, uint32_t count);

void *huge_tls_malloc(size_t sz);
void huge_tls_free(void *ptr);

static inline void * huge_xmalloc(uint32_t size)
{
        mem_pool_t *mem_pool = mem_pool_get(MEMORY_TYPE_INDEX_MALLOC);
        assert(mem_pool);
        return mem_pool_alloc(mem_pool, size);
}

static inline void huge_xfree(void *ptr)
{
        mem_pool_t *mem_pool = mem_pool_get(MEMORY_TYPE_INDEX_MALLOC); 

        mem_pool_free(mem_pool, ptr);
}

#if ENABLE_HUGE_MALLOC
static inline int huge_malloc(void **ptr, size_t size)
{
        *ptr = huge_xmalloc(size);
        if(unlikely(!*ptr))
                return ENOMEM;

        return 0;
}

static inline void huge_free(void **ptr)
{
        if (likely(*ptr != NULL)) {
                huge_xfree(*ptr);
        } else {
                //YASSERT(0);
        }

        *ptr = NULL;
}

#else 

#define huge_malloc ymalloc
#define huge_free yfree

#endif
#endif
